#include "rep/rep.hpp"

#include "rep/running.hpp"

#include "vm/opcodes.hpp"
#include "vm/handlers.hpp"

using namespace vm;

namespace rep{

  Continuation endContinuation = Continuation(NULL, NULL, NULL, 0);

  bool Continuation::ended(){
    Instruction pc = code->code[offset];
    return pc.op == END;
  }
  
  Continuation Continuation::next(){
    Instruction pc = code->code[offset];
    //pc + 1; If we need something different, use CALL or GO_CONT.
    //Blocks of coode must end in a CALL or GO_CONT
    Continuation standard_next = Continuation(stack, env, code, offset+1);
    switch (pc.op){
    case (NOOP):
      return handle_noop(stack, env, pc, standard_next);
    case (BUILTIN):
      return handle_builtin(stack, env, pc, standard_next);
    case (CALL):
      return handle_call(stack, env, pc, standard_next);
    case (GO_CONT):
      return handle_go_cont(stack, env, pc, standard_next);
    case (MAKE_CONT):
      return handle_make_cont(stack, env, pc, standard_next);
    case (LOAD):
      return handle_load(stack, env, pc, standard_next);
    case (STORE):
      return handle_store(stack, env, pc, standard_next);
    case (END):
      return handle_end(stack, env, pc, standard_next);
    }
    return endContinuation;
  }

  Continuation Continuation::pop(Slot* fill){
    assert(stack != NULL);
    return Continuation(stack->pop(fill), env, code, offset);      
  }

  Continuation Continuation::push(const Slot& ret){
    return Continuation(stack->push(ret), env, code, offset);
  }

  void ContinuationHelper::assign(Slot* to, Continuation* cont){
    to->tag = Slot::CONTINUE;
    to->cont = cont;
  }
};
